package ua.kharkov.knure.mikhaylov.st4.db.management;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import ua.kharkov.knure.mikhaylov.st4.db.entities.Account;
import ua.kharkov.knure.mikhaylov.st4.db.entities.Card;
import ua.kharkov.knure.mikhaylov.st4.db.entities.Payment;
import ua.kharkov.knure.mikhaylov.st4.db.entities.User;
import ua.kharkov.knure.mikhaylov.st4.db.entities.Valuta;
import ua.kharkov.knure.mikhaylov.st4.db.enums.AccountState;
import ua.kharkov.knure.mikhaylov.st4.db.enums.PaymentState;
import ua.kharkov.knure.mikhaylov.st4.db.enums.Role;
import ua.kharkov.knure.mikhaylov.st4.settings.DataStore;
import ua.kharkov.knure.mikhaylov.st4.settings.Field;

/**
 * This class is used for entity extraction from result set, not for zerg
 * vespene gas gathering.
 * 
 * @author Saint
 * 
 */
public class Extractor {

	private static Extractor instance;

	private Extractor() {
	}

	/**
	 * Singleton
	 * 
	 * @return
	 */
	public static Extractor getInstance() {
		if (instance == null) {
			synchronized (Extractor.class) {
				if (instance == null) {
					instance = new Extractor();
				}
			}
		}
		return instance;
	}

	/**
	 * Extracts user from result set
	 * 
	 * @param rs
	 *            - result set
	 * @return extracted user
	 * @throws SQLException
	 */
	public User extractUser(ResultSet rs) throws SQLException {
		User user = new User();
		user.setId(rs.getLong(Field.ID));
		user.setLogin(rs.getString(Field.USER_LOGIN));
		user.setPassword(rs.getString(Field.USER_PASSWORD));
		user.setFirstName(rs.getString(Field.USER_FIRST_NAME));
		user.setLastName(rs.getString(Field.USER_LAST_NAME));
		user.setRole(Role.values()[rs.getInt(Field.USER_ROLE)]);
		return user;
	}

	/**
	 * Extracts users list from result set
	 * 
	 * @param rs
	 *            - result set
	 * @return users list
	 * @throws SQLException
	 */
	public List<User> extractAllUsers(ResultSet rs) throws SQLException {
		List<User> users = new ArrayList<User>();
		while (rs.next()) {
			users.add(extractUser(rs));
		}
		return users;
	}

	/**
	 * Extracts valutas from result set
	 * 
	 * @param rs
	 *            - result set
	 * @return valutas list
	 * @throws SQLException
	 */
	public List<Valuta> extractAllValutas(ResultSet rs) throws SQLException {
		List<Valuta> valutas = new ArrayList<Valuta>();
		while (rs.next()) {
			valutas.add(extractValuta(rs));
		}
		return valutas;
	}

	/**
	 * Extracts a single valuta from result set
	 * 
	 * @param rs
	 *            - result set
	 * @return valuta
	 * @throws SQLException
	 */
	public Valuta extractValuta(ResultSet rs) throws SQLException {
		Valuta valuta = new Valuta();
		valuta.setId(rs.getLong(Field.ID));
		valuta.setFullName(rs.getString(Field.VALUTA_FULL_NAME));
		valuta.setShortName(rs.getString(Field.VALUTA_SHORT_NAME));
		return valuta;
	}

	/**
	 * Extracts a single account from result set. Warning: does not assign user
	 * 
	 * @param rs
	 *            - result set
	 * @return account
	 * @throws SQLException
	 */
	public Account extractAccount(ResultSet rs) throws SQLException {
		Account account = new Account();
		account.setId(rs.getLong(Field.ID));
		account.setBalance(rs.getDouble(Field.ACCOUNT_BALANCE));
		account.setValuta(DataStore.getValutas().get(
				rs.getLong(Field.ACCOUNT_VALUTA_ID)));
		// we don't assign user here because we'll do it later
		account.setAccountState(AccountState.values()[rs
				.getInt(Field.ACCOUNT_STATE_ID)]);
		return account;
	}

	/**
	 * Extracts a single account from result set. Warning: this method is almost
	 * a duplicate because of a lack of time
	 * 
	 * @param rs
	 *            - result set for extraction
	 * @param extractUser
	 *            - to set user or not to set
	 * @return extracted account
	 */
	public Account extractAccount(ResultSet rs, boolean extractUser)
			throws SQLException {
		Account account = new Account();
		account.setId(rs.getLong(Field.ID));
		account.setBalance(rs.getDouble(Field.ACCOUNT_BALANCE));
		account.setValuta(DataStore.getValutas().get(
				rs.getLong(Field.ACCOUNT_VALUTA_ID)));
		if (extractUser) {
			account.setUser(extractUser(rs));
		}
		account.setAccountState(AccountState.values()[rs
				.getInt(Field.ACCOUNT_STATE_ID)]);
		return account;
	}

	/**
	 * Extracts card. Warning: does not assign account
	 * 
	 * @param rs
	 *            - result set
	 * @return card
	 * @throws SQLException
	 */
	public Card extractCard(ResultSet rs) throws SQLException {
		Card card = new Card();
		card.setId(rs.getLong(Field.ID));
		card.setNumber(rs.getInt(Field.CARD_NUMBER));
		card.setSecurityCode(rs.getInt(Field.CARD_SECURITY_CODE));
		// we don't assign account here because we'll do it later
		return card;
	}

	/**
	 * Extracts payment
	 * 
	 * @param rs
	 *            - rsult set
	 * @return payment
	 * @throws SQLException
	 */
	public Payment extractPayment(ResultSet rs) throws SQLException {
		Payment payment = new Payment();
		payment.setId(rs.getLong(Field.ID));
		payment.setPaymentState(PaymentState.values()[rs
				.getInt(Field.PAYMENT_STATE_ID)]);
		payment.setPaymentDate(rs.getDate(Field.PAYMENT_DATE));
		payment.setVal(rs.getDouble(Field.PAYMENT_VALUE));
		payment.setReciever(DBManager.getInstance().findAccountById(
				rs.getLong(Field.PAYMENT_RECIEVER_ID)));
		payment.setPayer(DBManager.getInstance().findAccountById(
				rs.getLong(Field.PAYMENT_PAYER_ID)));
		return payment;
	}
}
